/* Copyright 2008 Bas van den Berg
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "myassert.h"

#include "World.h"
#include "Area.h"
#include "Room.h"
#include "Session.h"
#include "MudPlayer.h"
#include "Logger.h"
#include "Error.h"
#include "StringBuilder.h"
#include "MudObject.h"

using namespace Chronos;
using namespace std;


World::World(EventServer& eventServer_, TaskQueue& taskQueue)
    : EventListener()
    , eventServer(eventServer_)
    , builder(taskQueue)
{
    eventServer.registerListener(Event::PLAYER_LOGIN, this);
    eventServer.registerListener(Event::PLAYER_LOGOUT, this);
}


World::~World() {
    eventServer.unregisterListener(this);
	
	for (AreasConstIter iter = areas.begin(); iter != areas.end(); ++iter) {
		delete iter->second;
	}
}


void World::load() {
    builder.loadItems();
    areas[1] = builder.getArea1();
    areas[2] = builder.getArea2();
}


void World::notify(Event::EventType eventType, Session& session) {
    switch(eventType) {
    case Event::PLAYER_LOGIN:
        addPlayer(session);
        break;
    case Event::PLAYER_LOGOUT:
        removePlayer(session); 
        break;
    default:
        break;
    }
}


void World::addPlayer(Session& session) {
    MudPlayer& player = session.getPlayer();
    LOG(INFO, "World: player %s enters the world", player.getName().c_str());
    int startRoomID = 3;    // HARDCODED
	int startArea = 1;		// HARDCODED
    areas[startArea]->addPlayer(player, startRoomID, player.getName() + " appears from nowhere.\n");
}


void World::removePlayer(Session& session) {
    MudPlayer& player = session.getPlayer();
	Room* room = player.getRoom();
	room->removePlayer(player, player.getName() + " disappears into thin air.\n");
    LOG(INFO, "World: player %s leaves the world", player.getName().c_str());
}


void World::movePlayer(MudPlayer& player, int newAreaID, int newRoomID,
			const string& arriveMsg, const string& leaveMsg)
{
	Area* newArea = getArea(newAreaID);
	Room* room = player.getRoom();
	room->removePlayer(player, leaveMsg);
	newArea->addPlayer(player, newRoomID, arriveMsg);
}


void World::printAreas(StringBuilder& buffer) const {
    buffer << "Areas:\n";
    for (AreasConstIter iter = areas.begin(); iter != areas.end(); ++iter) {
        buffer << "   [" << iter->first << "] " << iter->second->getName() << '\n';
    }
}


void World::printStatus(StringBuilder& buffer) const {
    buffer << "  World: " << areas.size() << " areas, " << Room::count << " rooms, " << MudObject::count << " objects\n";
}


KillStats& World::getKills() { return kills; }


const Area* World::findArea(int areaID) const {
    AreasConstIter iter = areas.find(areaID);
    if (iter == areas.end()) return 0;
    return iter->second;
}


Area* World::getArea(int areaID) const {
	AreasConstIter iter = areas.find(areaID);
	if (iter == areas.end()) throw MudError("World: Area not found!");
	return iter->second;
}

